package algorithm

/*
 * File: fixedWindow.go
 * Created Date: 2022-07-25 02:35:50
 */
import (
	"time"
)

type FixedWindowLimiter struct {
	windowStart  time.Time // 窗口开始时间
	threshold    int       // 阈值qps,每秒请求上限
	currentCount int       // 当前请求数
}

// 初始化
func NewFixedWindowLimiter(threshold int) FixedWindowLimiter {
	return FixedWindowLimiter{
		windowStart:  time.Now(),
		threshold:    threshold,
		currentCount: 0,
	}
}

// Limit
func (l *FixedWindowLimiter) Limit() bool {
	if time.Since(l.windowStart) > 1*time.Second {
		l.windowStart = time.Now()
		l.currentCount = 0
	}
	l.currentCount++

	return l.currentCount > l.threshold
}

func (l *FixedWindowLimiter) CurrentCount() int {
	return l.currentCount
}
func (l *FixedWindowLimiter) Threshold() int {
	return l.threshold
}

/**
 * @Description: 固定窗口，计数器
 * @Keyword:
 * @Author: kami
 * @Date: 2022/8/10 14:28
 **/
type counter struct {
	Maximal int
	Period  time.Duration
	count   int
	tick    int64 // in nanosecond
}

func (s *counter) Take(count int) bool {
	if time.Now().UnixNano() > s.tick {
		// if timeout, reset counter regally at first
		s.count = 0
		s.tick = time.Now().Add(s.Period).UnixNano()
	}

	s.count += count            // it's acceptable in HPC scene
	return s.count <= s.Maximal // it's acceptable in HPC scene
}
